﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;

namespace Pittypat
{
    /// <summary>
    /// 表示一个布尔值。
    /// </summary>
    public struct @bool : IPrimitive
    {
        /// <summary>
        /// 将指定的字符串解析为一个 @bool 值。
        /// </summary>
        /// <param name="s">要解析的字符串。</param>
        /// <returns>一个 @bool 或 null。</returns>
        public static @bool? Parse(string s)
        {
            s = (s ?? "false").ToLower().Trim();

            if (s == "true" || s == "t" || s == "1" || s == "yes" || s == "y" || s == "on" || s == "是")
            {
                return true;
            }

            if (s == "false" || s == "f" || s == "0" || s == "no" || s == "n" || s == "off" || s == "否")
            {
                return false;
            }

            return null;
        }

        /// <summary>
        /// 比较两个值是否相等。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public static bool operator ==(@bool x, @bool y)
        {
            return x.value == y.value;
        }

        /// <summary>
        /// 比较两个值是否不相等。
        /// </summary>
        /// <param name="x">第一个值。</param>
        /// <param name="y">第二个值。</param>
        /// <returns>如果两个值不相等，则返回 true，否则返回 false。</returns>
        public static bool operator !=(@bool x, @bool y)
        {
            return x.value != y.value;
        }

        /// <summary>
        /// 对 @bool 值取反。
        /// </summary>
        /// <param name="x">一个 @bool 值。</param>
        /// <returns>如果 x 为 false，则返回 true，否则返回 false。</returns>
        public static @bool operator !(@bool x)
        {
            return !x.value;
        }

        private bool value;

        /// <summary>
        /// 初始化 @bool 结构的新实例。
        /// </summary>
        /// <param name="value">结构的值。</param>
        public @bool(bool value)
        {
            this.value = value;
        }

        /// <summary>
        /// 将当前值转换为 bool 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator bool(@bool value)
        {
            return value.value;
        }

        /// <summary>
        /// 将指定的值转换为 @bool 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator @bool(bool value)
        {
            return new @bool(value);
        }

        /// <summary>
        /// 将指定的值转换为 @bool 类型的值。
        /// </summary>
        /// <param name="value">要转换的值。</param>
        /// <returns>转换后的值。</returns>
        public static implicit operator @bool(string value)
        {
            return Parse(value) ?? false;
        }

        /// <summary>
        /// 判断两个值是否相等。
        /// </summary>
        /// <param name="obj">要比较的值。</param>
        /// <returns>如果两个值相等，则返回 true，否则返回 false。</returns>
        public override bool Equals(object obj)
        {
            if (obj is @bool)
            {
                return this.value == ((@bool)obj).value;
            }

            if (obj is bool)
            {
                return this.value == (bool)obj;
            }

            return false;
        }

        /// <summary>
        /// 返回此值的哈希代码。
        /// </summary>
        /// <returns>此值的哈希代码。</returns>
        public override int GetHashCode()
        {
            return this.value.GetHashCode();
        }

        /// <summary>
        /// 返回此值的字符串表示形式。
        /// </summary>
        /// <returns>此值的字符串表示形式。</returns>
        public override string ToString()
        {
            return this.ToString(null);
        }

        #region IPrimitive Members

        object IPrimitive.Value
        {
            get
            {
                return this.value;
            }
        }

        /// <summary>
        /// 将当前对象作为 JSON 字符串写入指定的文本流。
        /// </summary>
        /// <param name="writer">目标文本流。</param>
        /// <exception cref="ArgumentNullException">writer 是 null。</exception>
        public void Write(System.IO.TextWriter writer)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            writer.Write(this.value ? "true" : "false");
        }

        #endregion

        #region IConvertible Members

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            return this.value;
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            return this.value ? (byte)1 : (byte)0;
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            return this.value ? 'T' : 'F';
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            return this.value ? DateTime.MinValue : DateTime.MaxValue;
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            return this.value ? 1m : 0m;
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            return this.value ? 1d : 0d;
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            return this.value ? (short)1 : (short)0;
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            return this.value ? 1 : 0;
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            return this.value ? 1L : 0L;
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            return this.value ? (sbyte)1 : (sbyte)0;
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            return this.value ? 1f : 0f;
        }

        string IConvertible.ToString(IFormatProvider provider)
        {
            return this.value ? "true" : "false";
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            return ((IConvertible)this.value).ToType(conversionType, provider);
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            return this.value ? (ushort)1 : (ushort)0;
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            return this.value ? 1U : 0U;
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            return this.value ? 1UL : 0UL;
        }

        #endregion

        #region IComparable Members

        int IComparable.CompareTo(object other)
        {
            if (other is @bool)
            {
                return this.value.CompareTo(((@bool)other).value);
            }

            return 1;
        }

        #endregion

        #region IFormattable Members

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <param name="formatProvider">用于格式化该值的 IFormatProvider。null 表示从操作系统的当前区域设置中获取数字格式信息。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        /// <remarks>
        /// null、g、G 返回资源文件中定义的字符串，比如中文的“是”或“否”，b、B 返回 True 或 False，n、N 返回数字 1 或 0，y、Y 返回 Yes 或 No。
        /// </remarks>
        public string ToString(string format, IFormatProvider formatProvider)
        {
            if (format == null)
            {
                return this.value ? "true" : "false";
            }

            if (format == "g")
            {
                return this.value ? "true" : "false";
            }

            if (format == "G")
            {
                return this.value ? "TRUE" : "FALSE";
            }

            if (format == "b")
            {
                return this.value.ToString().ToLower();
            }

            if (format == "B")
            {
                return this.value.ToString().ToUpper();
            }

            if (format == "n" || format == "N")
            {
                return this.value ? "1" : "0";
            }

            if (format == "y")
            {
                return this.value ? "yes" : "no";
            }

            if (format == "Y")
            {
                return this.value ? "YES" : "NO";
            }

            return format;
        }

        /// <summary>
        /// 使用指定的格式格式化当前实例的值。
        /// </summary>
        /// <param name="format">指定要使用的格式的 String。</param>
        /// <returns>一个 String，包含具有指定格式的当前实例的值。</returns>
        public string ToString(string format)
        {
            return this.ToString(format, null);
        }

        #endregion
    }
}
